package com.puzzlebazar.client.util;

import java.io.Serializable;


public class Vec2i implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -3061501520823108602L;

	public Vec2i() {
		this.x = 0;
		this.y = 0;
	}
	public Vec2i(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public Vec2i(Vec2i from) {
		if( from == null ) {
			this.x = 0;
			this.y = 0;
		} else
		{
			this.x = from.x;
			this.y = from.y;
		}
	}
	public int x;
	public int y;
	public final static int WEST  = 3;
	public final static int SOUTH = 2;
	public final static int EAST  = 1;
	public final static int NORTH = 0;
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Vec2i other = (Vec2i) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
	/**
	 * Advances a 2D location vector one step in the given direction
	 * 
	 * @param vec The vector to advance 
	 * @param direction The direction to advance in
	 * @throws Exception
	 */
	public static void advanceInDirection(Vec2i vec, int direction) throws Exception {
		switch ( direction ) {
		case NORTH: vec.y--; return;
		case EAST: vec.x++; return;
		case SOUTH: vec.y++; return;
		case WEST: vec.x--; return;
		}		
		throw new Exception( "Invalid direction" );
	}
	/**
	 * @param direction The original direction
	 * @return The opposite direction
	 * @throws Exception
	 */
	public static int oppositeDirection(int direction) throws Exception {
		switch ( direction ) {
		case NORTH: return SOUTH;
		case EAST: return WEST;
		case SOUTH: return NORTH;
		case WEST: return EAST;
		}
		throw new Exception( "Invalid direction" );
	}
	/**
	 * Return the cardinal direction going from the
	 * first location to the second 
	 * 
	 * @param from First location
	 * @param to Second location
	 * @return The cardinal direction from the first location to the second (NORTH, EAST, SOUTH, WEST)
	 * @throws Exception If the locations are not in a direct line (horizontal or vertical)
	 */
	public static int findDirection(Vec2i from, Vec2i to) throws Exception {
		int direction = -1;
		if( from.x == to.x ) {
			if( from.y < to.y )
				direction = SOUTH;
			else if( from.y > to.y )
				direction = NORTH;
		}
		else if( from.y == to.y ) {
			if( from.x < to.x )
				direction = EAST;
			else if( from.x > to.x )
				direction = WEST;
		}
		if( direction < 0 ) throw new Exception( "Specified locations not horizontal or vertical" );
		
		return direction;
	}
	
	/**
	 * Creates a copy of the passed vector
	 * 
	 * @param vec Vector to copy
	 */
	public void copy(Vec2i vec) {
		if( vec == null ) {
			x = 0;
			y = 0;
		}
		x = vec.x;
		y = vec.y;
	}
	
	/**
	 * Creates a size string '??x??' based on the passed vector
	 * 
	 * @param size The Vec2i to convert to a size string
	 * @return The corresponding size string
	 */
	public String toSizeString() {
		return Integer.toString( x ) + "x" + Integer.toString( y );
	}
	
	/**
	 * Updates this Vec2i based on the passed size string '??x??'
	 * 
	 * @param sizeString The size string to convert to a Vec2i
	 */
	public void fromSizeString(String sizeString) {
		
		String[] result = sizeString.split( "x" );
		if( result.length != 2 ) {
			x = -1;
			y = -1;
		}
		try {
			x = Integer.parseInt(result[0]); 
			y = Integer.parseInt(result[1]); 
		}
		catch( Exception e ) {
			x = -1;
			y = -1;
		}
		
	}

	/**
	 * Creates a Vec2i base on the passed size string '??x??'
	 * 
	 * @param sizeString The size string to convert to a Vec2i
	 * @return The corresponding Vec2i
	 */
	public static Vec2i createFromSizeString(String sizeString) {
		Vec2i result = new Vec2i();
		result.fromSizeString( sizeString );
		return result;
	}
	
	/**
	 * Given two opposite cells of a rectangle, find the top-left vertex.
	 * BE CAREFUL: Passed locations must be for cells, not vertices.
	 * For vertices, use getTopLeft()
	 * 
	 * @param locFrom Cell at one corner of the rectangle 
	 * @param locTo Cell at the opposite corner of the rectangle
	 * @return The location of the top-left vertex
	 */
	public static Vec2i getTopLeftVertex(Vec2i locFrom, Vec2i locTo) {
		return new Vec2i( 
				Math.min( locFrom.x, locTo.x ),
				Math.min( locFrom.y, locTo.y ) );
	}

	/**
	 * Given two opposite cells of a rectangle, find the bottom-right vertex.
	 * BE CAREFUL: Passed locations must be for cells, not vertices.
	 * For vertices, use getBottomRight()
	 * 
	 * @param locFrom Cell at one corner of the rectangle 
	 * @param locTo Cell at the opposite corner of the rectangle
	 * @return The location of the bottom-right vertex
	 */
	public static Vec2i getBottomRightVertex(Vec2i locFrom, Vec2i locTo) {
		return new Vec2i( 
				Math.max( locFrom.x, locTo.x )+1,
				Math.max( locFrom.y, locTo.y )+1 );
	}
	
	/**
	 * Given two opposite cells (or vertices) of a rectangle, find the top-left cell (or vertex).
	 * 
	 * @param locFrom Cell (or vertex) at one corner of the rectangle 
	 * @param locTo Cell (or vertex) at the opposite corner of the rectangle
	 * @return The location of the top-left cell (or vertex)
	 */
	public static Vec2i getTopLeft(Vec2i locFrom, Vec2i locTo) {
		return getTopLeftVertex( locFrom, locTo );
	}
	
	/**
	 * Given two opposite cells (or vertices) of a rectangle, find the bottom-right cell (or vertex).
	 * 
	 * @param locFrom Cell (or vertex) at one corner of the rectangle 
	 * @param locTo Cell (or vertex) at the opposite corner of the rectangle
	 * @return The location of the bottom-right cell (or vertex)
	 */
	public static Vec2i getBottomRight(Vec2i locFrom, Vec2i locTo) {
		return new Vec2i( 
				Math.max( locFrom.x, locTo.x ),
				Math.max( locFrom.y, locTo.y ) );
	}
	
}